package com.hzit.seckill.service.impl;

import com.alibaba.fastjson2.JSON;
import com.hzit.common.constant.HzitBusinessConstants;
import com.hzit.common.utils.IdWorker;
import com.hzit.seckill.entity.SeckillGoods;
import com.hzit.seckill.entity.SeckillOrder;
import com.hzit.seckill.entity.SeckillStatus;
import com.hzit.seckill.interceptor.LoginInterceptor;
import com.hzit.seckill.service.ISeckillGoodsService;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.Date;

/**
 * 类名：
 * 作者：WF
 * 功能：异步下单
 */
@Component
public class MultiThreadSeckillOrder {
	@Autowired
	private StringRedisTemplate redisTemplate;
	@Autowired
	private ISeckillGoodsService goodsService;
	@Autowired
	private IdWorker idWorker;
	@Autowired
	private RedissonClient redissonClient;
	// 异步下单
	@Async
	public void fareOrder(String id) {
		//0. 获取信号量,使用限号量进行限流
		RSemaphore semaphore = redissonClient.getSemaphore(HzitBusinessConstants.SECKILL_LIMIT_FLOW_PREFIX + id);
		boolean b = semaphore.tryAcquire();
		if(b){
			//1. 从右侧弹出一个需要购买的商品，如果弹出的是null，证明，此商品己卖完！ （避免商品超卖）
			String seckillIdStr = redisTemplate.boundListOps(HzitBusinessConstants.SECKILL_OVERSELL_PREFIX + id).rightPop();
			if(seckillIdStr == null){   // 引时弹出的商品为null，证明己销售一空
				clearOrderQueueInfo();
				throw new RuntimeException("商品己售罄！");
			}
			//2. 为了公平购买，我们从redis中list中的右边弹出一个用户状态值
			String s = redisTemplate.boundListOps(HzitBusinessConstants.SECKILL_ORDER_QUEUE).rightPop();
			SeckillStatus seckillStatus = JSON.parseObject(s, SeckillStatus.class);
			//3. 得到商品id
			Long secKillId = seckillStatus.getSecKillId();
			//4. 得到时间段
			String time = seckillStatus.getTime();

			//5. 进行商品的精准控制
			String str = (String) redisTemplate.boundHashOps(HzitBusinessConstants.SECKILL_GOODS_PREFIX + time).get(secKillId + "");
			SeckillGoods goods = JSON.parseObject(str, SeckillGoods.class);
			//5.1 将需要精准购买的商品，库存自增-1
			Long count = redisTemplate.boundHashOps(HzitBusinessConstants.SECKILL_PRECISE).increment(secKillId + "", -1);
			//5.2 将其重新设置回库存
			goods.setStockCount(Math.toIntExact(count));

			//5. 从redis中查询出秒杀商品
			if(goods == null || goods.getStockCount() == 0){
				// 5.1 修改商品回数据库
				goodsService.updateById(goods);
				// 5.2 从redis中删除此商品
				redisTemplate.opsForHash().delete(HzitBusinessConstants.SECKILL_GOODS_PREFIX + time, secKillId + "");
			}else{  // 如果存在此商品，重新放回到redis中
				redisTemplate.opsForHash().put(HzitBusinessConstants.SECKILL_GOODS_PREFIX + time, secKillId + "",JSON.toJSONString(goods));
			}
			//6. 开始准备订单，下单处理
			SeckillOrder order = new SeckillOrder();
			String login = LoginInterceptor.threadLocal.get().getLogin();
			long oid = idWorker.nextId();
			order.setId(oid);
			order.setCreateTime(LocalDateTime.now());
			order.setMoney(goods.getCostPrice());
			order.setSeckillId(secKillId );
			order.setStatus("0");
			order.setUserId(login);
			//7. 将秒杀订单放到redsi中
			redisTemplate.opsForValue().set(HzitBusinessConstants.SECKILL_REDIS_ORDER_PREFIX + login,JSON.toJSONString(order));

			//8. 重新设置用户状态值
			seckillStatus.setStatus(2);
			seckillStatus.setOrderId(idWorker.nextId());
			//9. 重新保存到redis中
			redisTemplate.opsForValue().set(HzitBusinessConstants.SECKILL_ORDER_QUEUE_BACK,JSON.toJSONString(seckillStatus));
		}
	}
	// 精空用户排队信息
	private void clearOrderQueueInfo() {
		redisTemplate.delete(HzitBusinessConstants.SECKILL_REPEAT_ORDER);
		redisTemplate.delete(HzitBusinessConstants.SECKILL_ORDER_QUEUE);
		redisTemplate.delete(HzitBusinessConstants.SECKILL_ORDER_QUEUE_BACK);
	}
}

